#!/bin/bash
# RedFire 数据库备份脚本
# 支持PostgreSQL、Redis和MongoDB的自动备份

set -e  # 出错时退出

# 配置变量
BACKUP_BASE_DIR="/backup"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/redfire_backup.log"
RETENTION_DAYS=30

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 日志函数
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE"
}

error() {
    echo -e "${RED}ERROR: $1${NC}" | tee -a "$LOG_FILE"
}

success() {
    echo -e "${GREEN}SUCCESS: $1${NC}" | tee -a "$LOG_FILE"
}

warning() {
    echo -e "${YELLOW}WARNING: $1${NC}" | tee -a "$LOG_FILE"
}

# 检查依赖
check_dependencies() {
    local deps=("pg_dump" "redis-cli" "mongodump")
    local missing=()
    
    for dep in "${deps[@]}"; do
        if ! command -v "$dep" &> /dev/null; then
            missing+=("$dep")
        fi
    done
    
    if [ ${#missing[@]} -gt 0 ]; then
        warning "以下工具未安装: ${missing[*]}"
        warning "某些备份功能可能不可用"
    fi
}

# 创建备份目录
create_backup_dir() {
    local backup_type=$1
    local backup_dir="$BACKUP_BASE_DIR/$backup_type/$DATE"
    
    mkdir -p "$backup_dir"
    echo "$backup_dir"
}

# PostgreSQL备份
backup_postgresql() {
    local db_name=${1:-"redfire_stage2"}
    local pg_host=${2:-"localhost"}
    local pg_port=${3:-"5432"}
    local pg_user=${4:-"redfire_prod"}
    
    log "开始备份PostgreSQL数据库: $db_name"
    
    if ! command -v pg_dump &> /dev/null; then
        error "pg_dump 未安装，跳过PostgreSQL备份"
        return 1
    fi
    
    local backup_dir=$(create_backup_dir "postgresql")
    local backup_file="$backup_dir/${db_name}_${DATE}.sql"
    
    # 执行备份
    if PGPASSWORD="$POSTGRES_PASSWORD" pg_dump \
        -h "$pg_host" \
        -p "$pg_port" \
        -U "$pg_user" \
        -d "$db_name" \
        --no-password \
        --verbose \
        --format=custom \
        --file="$backup_file" 2>> "$LOG_FILE"; then
        
        # 压缩备份文件
        gzip "$backup_file"
        backup_file="${backup_file}.gz"
        
        # 计算文件大小
        local size=$(du -h "$backup_file" | cut -f1)
        
        success "PostgreSQL备份完成: $backup_file (大小: $size)"
        return 0
    else
        error "PostgreSQL备份失败"
        return 1
    fi
}

# Redis备份
backup_redis() {
    local redis_host=${1:-"localhost"}
    local redis_port=${2:-"6379"}
    
    log "开始备份Redis数据库"
    
    if ! command -v redis-cli &> /dev/null; then
        error "redis-cli 未安装，跳过Redis备份"
        return 1
    fi
    
    local backup_dir=$(create_backup_dir "redis")
    local backup_file="$backup_dir/redis_${DATE}.rdb"
    
    # 执行备份
    local cmd="redis-cli -h $redis_host -p $redis_port"
    
    if [ -n "$REDIS_PASSWORD" ]; then
        cmd="$cmd -a $REDIS_PASSWORD"
    fi
    
    if $cmd --rdb "$backup_file" 2>> "$LOG_FILE"; then
        # 压缩备份文件
        gzip "$backup_file"
        backup_file="${backup_file}.gz"
        
        # 计算文件大小
        local size=$(du -h "$backup_file" | cut -f1)
        
        success "Redis备份完成: $backup_file (大小: $size)"
        return 0
    else
        error "Redis备份失败"
        return 1
    fi
}

# MongoDB备份
backup_mongodb() {
    local db_name=${1:-"redfire_config"}
    local mongo_host=${2:-"localhost"}
    local mongo_port=${3:-"27017"}
    
    log "开始备份MongoDB数据库: $db_name"
    
    if ! command -v mongodump &> /dev/null; then
        error "mongodump 未安装，跳过MongoDB备份"
        return 1
    fi
    
    local backup_dir=$(create_backup_dir "mongodb")
    local dump_dir="$backup_dir/dump"
    
    # 构建命令
    local cmd="mongodump --host $mongo_host:$mongo_port --db $db_name --out $dump_dir"
    
    if [ -n "$MONGO_USERNAME" ]; then
        cmd="$cmd --username $MONGO_USERNAME"
    fi
    
    if [ -n "$MONGO_PASSWORD" ]; then
        cmd="$cmd --password $MONGO_PASSWORD"
    fi
    
    if [ -n "$MONGO_AUTH_DB" ]; then
        cmd="$cmd --authenticationDatabase $MONGO_AUTH_DB"
    fi
    
    # 执行备份
    if $cmd 2>> "$LOG_FILE"; then
        # 打包和压缩
        local archive_file="$backup_dir/mongodb_${db_name}_${DATE}.tar.gz"
        tar -czf "$archive_file" -C "$backup_dir" dump
        
        # 删除临时目录
        rm -rf "$dump_dir"
        
        # 计算文件大小
        local size=$(du -h "$archive_file" | cut -f1)
        
        success "MongoDB备份完成: $archive_file (大小: $size)"
        return 0
    else
        error "MongoDB备份失败"
        return 1
    fi
}

# 清理过期备份
cleanup_old_backups() {
    log "开始清理过期备份 (保留 $RETENTION_DAYS 天)"
    
    local cleanup_count=0
    
    for backup_type in postgresql redis mongodb; do
        local type_dir="$BACKUP_BASE_DIR/$backup_type"
        
        if [ -d "$type_dir" ]; then
            # 查找并删除过期文件
            while IFS= read -r -d '' file; do
                rm -rf "$file"
                cleanup_count=$((cleanup_count + 1))
                log "删除过期备份: $file"
            done < <(find "$type_dir" -type f -mtime +$RETENTION_DAYS -print0 2>/dev/null)
            
            # 删除空目录
            find "$type_dir" -type d -empty -delete 2>/dev/null || true
        fi
    done
    
    if [ $cleanup_count -gt 0 ]; then
        success "清理完成，删除了 $cleanup_count 个过期备份"
    else
        log "没有找到过期备份文件"
    fi
}

# 发送通知
send_notification() {
    local status=$1
    local message=$2
    
    # 这里可以添加邮件、钉钉、企业微信等通知方式
    if [ "$status" = "success" ]; then
        log "备份成功通知: $message"
    else
        log "备份失败通知: $message"
    fi
    
    # 示例：发送邮件通知
    if command -v mail &> /dev/null && [ -n "$NOTIFICATION_EMAIL" ]; then
        echo "$message" | mail -s "RedFire 备份通知 - $status" "$NOTIFICATION_EMAIL"
    fi
}

# 主函数
main() {
    log "======== RedFire 数据库备份开始 ========"
    
    # 检查依赖
    check_dependencies
    
    # 创建日志目录
    mkdir -p "$(dirname "$LOG_FILE")"
    
    # 加载环境变量
    if [ -f "/etc/redfire/backup.env" ]; then
        source "/etc/redfire/backup.env"
    elif [ -f "../configs/environments/redfire.env" ]; then
        source "../configs/environments/redfire.env"
    fi
    
    local success_count=0
    local total_count=0
    local failed_services=()
    
    # PostgreSQL备份
    if [ "${BACKUP_POSTGRESQL:-true}" = "true" ]; then
        total_count=$((total_count + 1))
        if backup_postgresql "$POSTGRES_DB" "$POSTGRES_HOST" "$POSTGRES_PORT" "$POSTGRES_USER"; then
            success_count=$((success_count + 1))
        else
            failed_services+=("PostgreSQL")
        fi
    fi
    
    # Redis备份
    if [ "${BACKUP_REDIS:-true}" = "true" ]; then
        total_count=$((total_count + 1))
        if backup_redis "$REDIS_HOST" "$REDIS_PORT"; then
            success_count=$((success_count + 1))
        else
            failed_services+=("Redis")
        fi
    fi
    
    # MongoDB备份
    if [ "${BACKUP_MONGODB:-false}" = "true" ]; then
        total_count=$((total_count + 1))
        if backup_mongodb "$MONGO_DB" "$MONGO_HOST" "$MONGO_PORT"; then
            success_count=$((success_count + 1))
        else
            failed_services+=("MongoDB")
        fi
    fi
    
    # 清理过期备份
    cleanup_old_backups
    
    # 生成报告
    log "======== 备份完成 ========"
    log "总服务数: $total_count"
    log "成功备份: $success_count"
    log "失败备份: $((total_count - success_count))"
    
    if [ ${#failed_services[@]} -gt 0 ]; then
        log "失败服务: ${failed_services[*]}"
    fi
    
    # 发送通知
    if [ $success_count -eq $total_count ]; then
        send_notification "success" "所有数据库备份成功完成"
        log "所有备份任务成功完成"
        exit 0
    else
        send_notification "failure" "部分数据库备份失败: ${failed_services[*]}"
        error "部分备份任务失败"
        exit 1
    fi
}

# 显示帮助信息
show_help() {
    cat << EOF
RedFire 数据库备份脚本

用法: $0 [选项]

选项:
    -h, --help              显示此帮助信息
    -p, --postgresql-only   仅备份PostgreSQL
    -r, --redis-only        仅备份Redis
    -m, --mongodb-only      仅备份MongoDB
    -c, --cleanup-only      仅清理过期备份
    --retention DAYS        设置保留天数 (默认: 30)

环境变量:
    POSTGRES_HOST           PostgreSQL主机 (默认: localhost)
    POSTGRES_PORT           PostgreSQL端口 (默认: 5432)
    POSTGRES_DB             PostgreSQL数据库名
    POSTGRES_USER           PostgreSQL用户名
    POSTGRES_PASSWORD       PostgreSQL密码
    
    REDIS_HOST              Redis主机 (默认: localhost)
    REDIS_PORT              Redis端口 (默认: 6379)
    REDIS_PASSWORD          Redis密码
    
    MONGO_HOST              MongoDB主机 (默认: localhost)
    MONGO_PORT              MongoDB端口 (默认: 27017)
    MONGO_DB                MongoDB数据库名
    MONGO_USERNAME          MongoDB用户名
    MONGO_PASSWORD          MongoDB密码
    MONGO_AUTH_DB           MongoDB认证数据库
    
    BACKUP_BASE_DIR         备份基础目录 (默认: /backup)
    NOTIFICATION_EMAIL      通知邮箱地址

示例:
    # 备份所有数据库
    $0
    
    # 仅备份PostgreSQL
    $0 --postgresql-only
    
    # 设置保留30天
    $0 --retention 30
    
    # 仅清理过期备份
    $0 --cleanup-only

EOF
}

# 解析命令行参数
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_help
            exit 0
            ;;
        -p|--postgresql-only)
            BACKUP_POSTGRESQL=true
            BACKUP_REDIS=false
            BACKUP_MONGODB=false
            shift
            ;;
        -r|--redis-only)
            BACKUP_POSTGRESQL=false
            BACKUP_REDIS=true
            BACKUP_MONGODB=false
            shift
            ;;
        -m|--mongodb-only)
            BACKUP_POSTGRESQL=false
            BACKUP_REDIS=false
            BACKUP_MONGODB=true
            shift
            ;;
        -c|--cleanup-only)
            cleanup_old_backups
            exit 0
            ;;
        --retention)
            RETENTION_DAYS="$2"
            shift 2
            ;;
        *)
            error "未知参数: $1"
            show_help
            exit 1
            ;;
    esac
done

# 执行主函数
main
